package thread;

/**
 * 多线程并发安全问题
 * 当多个线程并发操作同一临界资源，由于线程切换实际不确定，导致操作顺序出现混乱
 * 从而引发不良后果。
 *
 */
public class SyncDemo1 {
    static boolean success1 = false;//第一个人是否取款成功
    static boolean success2 = false;//第二个人是否取款成功
    public static void main(String[] args) {
        Bank bank = new Bank();
        int sum = 0;//记录一共尝试了多少次
        while(true) {
            sum++;
            Thread t1 = new Thread() {
                public void run() {
                    success1 = bank.getMoney(20000);
                }
            };
            Thread t2 = new Thread() {
                public void run() {
                    success2 = bank.getMoney(20000);
                }
            };
            t1.start();
            t2.start();

            try {
                Thread.sleep(10);//让主线程等待一会(t1,t2执行完毕)
            } catch (InterruptedException e) {
            }

            if (success1 && success2) {
                System.out.println("都取出20000！出现了问题!一共尝试了:"+sum+"次");
                break;
            } else {
                //不成功重新将钱存起来，再次尝试重新取款
                bank.saveAccount(20000);
                success1 = false;
                success2 = false;
            }
        }
    }
}

class Bank{
    private int account=20000;//账号余额
    //当一个方法被synchronized修饰后，这个方法称为同步方法，多个线程不能同时执行它
    //将异步操作改为同步操作可以有效的解决并发安全问题
    public synchronized boolean getMoney(int money){
        //首先先查看余额
        int account = getAccount();
        //判断是否足够
        if(account>=money){
            account = account-money;//计算取款后的余额
            Thread.yield();//yield方法用于主动让线程放弃本次剩余时间片，这里是为了模式执行到saveAccount之前时间片耗尽，发生线程切换
            saveAccount(account);//保存新的余额
            return true;//允许出钞
        }
        return false;//拒绝出钞
    }

    public void saveAccount(int account){
        this.account = account;
    }

    //查询余额操作
    public int getAccount() {
        return account;
    }
}




